Skip to content

Add Antivirus Scanner#19329

Merged
MikeAlhayek merged 26 commits into
mainfrom
ma/upload-file-scanner
Jun 19, 2026
Merged

Add Antivirus Scanner#19329
MikeAlhayek merged 26 commits into
mainfrom
ma/upload-file-scanner

Conversation

@MikeAlhayek

@MikeAlhayek MikeAlhayek commented Jun 3, 2026

Copy link
Copy Markdown
Member

This pull request introduces a new ClamAV antivirus integration for Orchard Core, enabling file scanning with ClamAV before storage. It adds a new OrchardCore.Antivirus module, Aspire host project, and related configuration and documentation updates. The key changes are grouped below:

ClamAV Antivirus Module Implementation:

  • Added a new OrchardCore.Antivirus module with ClamAV support, including options (ClamAvOptions), a connection manager (ClamAvConnection, ClamAvConnectionFactory), and a file event handler (ClamAvFileEventHandler) that scans files using ClamAV before saving. This ensures uploaded files are checked for viruses and rejected if infected. [1] [2] [3] [4]
  • Registered the module and feature in Manifest.cs with metadata and description.

Aspire Host Integration:

  • Introduced a new OrchardCore.AspireHost project configured to orchestrate the ClamAV container via Aspire, including resource definition (ClamAVResource), program setup (Program.cs), and related configuration files. This enables running ClamAV alongside Orchard Core in a distributed environment. [1] [2] [3] [4] [5] [6] [7]

Solution and Dependency Updates:

  • Added the new projects to the solution (OrchardCore.slnx) and included the Aspire package version in Directory.Packages.props. [1] [2] [3]
  • Minor project file cleanup for OrchardCore.Cms.Web.csproj.

Documentation:

  • Updated documentation navigation to include the ClamAV Antivirus Scanner module.

MikeAlhayek

This comment was marked as off-topic.

Comment thread src/OrchardCore/OrchardCore.FileStorage.Abstractions/IAntivirusScanner.cs Outdated
Comment thread src/OrchardCore/OrchardCore.Media.Core/DefaultMediaFileStore.cs Outdated
Comment thread src/OrchardCore/OrchardCore.Media.Core/DefaultMediaFileStore.cs Outdated
@MikeAlhayek

Copy link
Copy Markdown
Member Author

@gvkries @sebastienros I made the changes we spoke about today. However, I added FileCreationService that handles invoking the events. Let me know your thoughts.

Comment thread src/docs/reference/modules/Antivirus/README.md Outdated
Comment thread src/OrchardCore/OrchardCore.Infrastructure.Abstractions/Result.cs
Comment thread src/OrchardCore/OrchardCore.Media.Core/DefaultMediaFileStore.cs Outdated
@gvkries

gvkries commented Jun 5, 2026

Copy link
Copy Markdown
Member

@gvkries @sebastienros I made the changes we spoke about today. However, I added FileCreationService that handles invoking the events. Let me know your thoughts.

I think that service is fine, but we could also just go with extension methods. Because I think we should not force all event handlers to be singletons, the additional service just adds overhead.

@MikeAlhayek

Copy link
Copy Markdown
Member Author

I think that service is fine, but we could also just go with extension methods. Because I think we should not force all event handlers to be singletons, the additional service just adds overhead.

@gvkries I addressed your feedback. Now the FileCreatingService is transient and the handlers can be registered in any form. I still like FileCreatingService over extension as it provides better UI, and the user will have to resolve a single service and it is stronger abstraction.

Comment thread src/OrchardCore/OrchardCore.Media.Core/DefaultMediaFileStore.cs Outdated
Co-authored-by: Georg von Kries <gvk@creativbox.net>
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts. Please resolve those before requesting a review.

@MikeAlhayek

Copy link
Copy Markdown
Member Author

@copilot please fix merge conflicts and merge main into this branch

Co-authored-by: MikeAlhayek <24724371+MikeAlhayek@users.noreply.github.com>

Copilot AI commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

@copilot please fix merge conflicts and merge main into this branch

Done in commit 0f40998: merged origin/main into this branch, resolved the merge conflict in src/OrchardCore/OrchardCore.Infrastructure.Abstractions/Result.cs, and validated with targeted tests.


namespace OrchardCore.Antivirus.ClamAV;

public sealed class ClamAvConnectionFactory : IDisposable

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these implementations could be private (not just this class)

/// The caller owns the original <paramref name="stream"/> and should dispose the returned
/// <see cref="FileCreatingResult"/> to clean up any replacement stream created by handlers.
/// </summary>
public async Task<FileCreatingResult> CreateAsync(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need an argument to specify ownership and the dispose behavior. By default any stream that is passed we now own and dispose it like StreamReader, GZipStream, SslStream, …). For instance public MyWrapper(Stream stream, ..., bool leaveOpen = false).

@@ -0,0 +1,22 @@
<Project Sdk="Aspire.AppHost.Sdk/13.4.1">

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's fine right now but we should put this version in a props file so this is updatable automatically (it's already 13.4.4)

@MikeAlhayek MikeAlhayek Jun 17, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Project Sdk="..." does not naturally flow from Directory.Packages.props. I added comment to ensure that we update the Sdk when updating the package version

$"tcp://{PrimaryEndpoint.Property(EndpointProperty.Host)}:{PrimaryEndpoint.Property(EndpointProperty.Port)}");
}

internal static class ClamAVResourceBuilderExtensions

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about making these available in the modules?
Same for configuration.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd keep them in OrchardCore.AspireHost for now so the runtime module doesn’t take an Aspire hosting dependency.

using Aspire.Hosting.ApplicationModel;
using OrchardCore.AspireHost;

var builder = DistributedApplication.CreateBuilder(args);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the goal of the app? Feels like a sample for ClamAV, not a generic "OrchardCore ApireHost".

We could say it's the beginning of such a big sample but there are nothing else than the AV right now...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Today it is effectively a ClamAV-oriented sample/bootstrap host. But this will be expanded later on by adding more useful services like Elasticsearch, Redis, etc so that we can use the Aspire host to make other services ready locally.

@MikeAlhayek MikeAlhayek requested a review from sebastienros June 17, 2026 22:34
@MikeAlhayek MikeAlhayek added this to the 4.x milestone Jun 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts. Please resolve those before requesting a review.

@MikeAlhayek MikeAlhayek merged commit 0bf3e02 into main Jun 19, 2026
13 checks passed
@MikeAlhayek MikeAlhayek deleted the ma/upload-file-scanner branch June 19, 2026 17:00
@hishamco hishamco modified the milestones: 4.x, 4.0 Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants